package com.sailing.xjpb.web.base.advice;

import com.sailing.xjpb.common.exception.SailingException;
import com.sailing.xjpb.common.web.ActionResult;
import com.sailing.xjpb.common.web.ResponseCode;
import com.sailing.xjpb.common.web.ResultUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.validation.BindException;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.multipart.MultipartException;

import javax.servlet.http.HttpServletRequest;

/**
 * 全局捕获异常
 *
 * @author YW
 * @see SailingException
 */
@ControllerAdvice
@Slf4j
public class SailingExceptionHandler {

    public static final String PARAM_EXCEPTION = "参数校验异常";

    /**
     * 普通异常捕获
     *
     * @param e 异常信息
     */
    @ExceptionHandler(value = Exception.class)
    @ResponseBody
    @ResponseStatus(value = HttpStatus.OK)
    public ActionResult<Boolean> exceptionHandle(Exception e, HttpServletRequest request) {
        log.error("系统异常： path= {} ", request.getRequestURI());
        log.error("系统未知错误", e);
        return ResultUtils.error(ResponseCode.SYSTEM_ERROR.code(), "系统未知错误，请联系管理员！", e);
    }

    /**
     * SailingException异常捕获
     *
     * @param e 异常信息
     */
    @ExceptionHandler(value = SailingException.class)
    @ResponseBody
    @ResponseStatus(value = HttpStatus.OK)
    public ActionResult<Boolean> serviceExceptionHandle(SailingException e, HttpServletRequest request) {
        log.error("系统发生SailingException异常： path= {} ", request.getRequestURI());
        log.error("系统发生SailingException异常", e);
        Throwable cause = e.getCause();
        return ResultUtils.error(e.getResponseCode(), e.getMessage(), cause != null ? cause : e);
    }

    /**
     * controller层参数标有Valid注解校验参数异常解析
     *
     * @param e 异常信息
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    @ResponseBody
    @ResponseStatus(value = HttpStatus.OK)
    public ActionResult<Boolean> handleMethodArgumentNotValidException(MethodArgumentNotValidException e,
                                                                       HttpServletRequest request) {
        log.error(PARAM_EXCEPTION + "-handleMethodArgumentNotValidException： path= {} ", request.getRequestURI(), e);
        log.error(PARAM_EXCEPTION + "-handleMethodArgumentNotValidException", e);
        FieldError fieldError = e.getBindingResult().getFieldError();
        String msg = PARAM_EXCEPTION;
        if (fieldError != null) {
            msg += "：field[" + fieldError.getField() + "]-" + fieldError.getDefaultMessage();
        }
        return ResultUtils.error(ResponseCode.B_3101.code(), msg, e);
    }

    /**
     * controller层参数标有Valid注解校验参数异常解析
     *
     * @param e 异常信息
     */
    @ExceptionHandler(BindException.class)
    @ResponseBody
    @ResponseStatus(value = HttpStatus.OK)
    public ActionResult<Boolean> handleBindException(BindException e, HttpServletRequest request) {
        log.error(PARAM_EXCEPTION + "-handleBindException： path= {} ", request.getRequestURI());
        log.error(PARAM_EXCEPTION + "-handleBindException", e);
        FieldError fieldError = e.getBindingResult().getFieldError();
        String msg = PARAM_EXCEPTION;
        if (fieldError != null) {
            msg += "：field[" + fieldError.getField() + "]-" + fieldError.getDefaultMessage();
        }
        return ResultUtils.error(ResponseCode.B_3101.code(), msg, e);
    }

    /**
     * 必填参数缺失异常
     *
     * @param e 异常信息
     * @see org.springframework.web.bind.annotation.RequestParam
     */
    @ExceptionHandler(MissingServletRequestParameterException.class)
    @ResponseBody
    @ResponseStatus(value = HttpStatus.OK)
    public ActionResult<Boolean> missingParameterException(MissingServletRequestParameterException e,
                                                           HttpServletRequest request) {
        log.error(PARAM_EXCEPTION + "-missingParameterException： path= {} ", request.getRequestURI());
        log.error(PARAM_EXCEPTION + "-missingParameterException", e);
        String msg = PARAM_EXCEPTION + "：参数[" + e.getParameterName() + "]缺失！";
        return ResultUtils.error(ResponseCode.B_3101.code(), msg, e);
    }

    /**
     * 文件上传异常
     *
     * @param e 异常信息
     */
    @ExceptionHandler(MultipartException.class)
    @ResponseBody
    @ResponseStatus(value = HttpStatus.OK)
    public ActionResult<Boolean> handleMultipartException(MultipartException e) {
        String msg = "文件上传失败：" + e.getMessage();
        log.error(msg, e);
        return ResultUtils.error(ResponseCode.B_3102.code(), msg, e);
    }

}
